/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef SAMPLE_SIMPLE_FILEDCREDENTIALPROVIDER_H_
#define SAMPLE_SIMPLE_FILEDCREDENTIALPROVIDER_H_

#include <string>

#include "Exception.h"
#include "reader/XmlReader.h"
#include "auth/Credential.h"
#include "auth/ICredentialProvider.h"

using aliyun::Exception;
using aliyun::reader::XmlReader;
using aliyun::auth::Credential;
using aliyun::auth::ICredentialProvider;

class FiledCredentialProvider : public ICredentialProvider {
  static const char CREDENTIAL_FILENAME[];
  static const char CURRENT_HEADER_PATH[];

 public:
  typedef std::string string;

  // implement
  Credential fresh() {
    Credential cred;

    string content = readFile(getCredentialFilePath());

    XmlReader reader;
    XmlReader::document* doc = reader.getDocument(content);
    std::vector<XmlReader::node*> kn = XmlReader::getElementsByTagName(doc, "AccessKeyId");
    std::vector<XmlReader::node*> sn = XmlReader::getElementsByTagName(doc, "AccessSecret");

    if (kn.size() != 0) {
      cred.setAccessKeyId(XmlReader::getContent(kn[0]));
    }
    if (sn.size() != 0) {
      cred.setAccessSecret(XmlReader::getContent(sn[0]));
    }
    return cred;
  }

  // singleton usage
  static ICredentialProvider* getProvider() {
    if (NULL == sProvider_) {
      static FiledCredentialProvider stub;
      sProvider_ = &stub;
    }
    return sProvider_;
  }

 private:
  static string readFile(string filename) {
    std::ifstream file(filename.c_str());
    if (!file) {
      throw Exception("file not found");
    }

    // get file length
    file.seekg(0, std::ios_base::end);
    long length = file.tellg();
    file.seekg(0, std::ios_base::beg);

    // read file content
    string content(length, '\0');
    file.read(&content[0], length);
    return content;
  }

  /**
   * here we suppose that, credential.xml in the same directory of current file
   **/
  static string getCredentialFilePath() {
    string cur(CURRENT_HEADER_PATH);
    int idx = cur.find_last_of('/');
    if (idx == string::npos) {
      idx = cur.find_last_of('\\');  // for windows
    }

    if (idx == string::npos) {
      return CREDENTIAL_FILENAME;
    }
    return cur.substr(0, idx + 1) + CREDENTIAL_FILENAME;
  }

  static ICredentialProvider* sProvider_;
};

ICredentialProvider* FiledCredentialProvider::sProvider_ = NULL;

const char FiledCredentialProvider::CREDENTIAL_FILENAME[] = "credential.xml";

// can not move this line to .cc file
const char FiledCredentialProvider::CURRENT_HEADER_PATH[] = __FILE__;

#endif  // SAMPLE_SIMPLE_FILEDCREDENTIALPROVIDER_H_
